package com.springboot.file.util;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import com.springboot.file.exception.BusinessException;
import com.springboot.file.util.regex.RegexUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.*;
import java.util.*;
import java.util.stream.Stream;

/**
 * 日期工具类
 * @author liuc
 */
@Slf4j
public class DateUtil {
    private DateUtil() {}
    private static final Map<String, ThreadLocal<SimpleDateFormat>> SDF_MAP = new HashMap<>(16);
    public static final Object LOCK_OBJ = new Object();
    /**
     * 考虑港股和美股 采用GMT-1时区来确定报表日 即T日的报表包含北京时间T日9时至T+1日9时的数据
     */
    public static final ZoneId TIMEZONE_GMT_1 = ZoneId.of("GMT-1");
    public static final ZoneId TIMEZONE_EST = ZoneId.of("US/Eastern");
    public static final ZoneId TIMEZONE_GMT8 = ZoneId.of("GMT+8");

    /**
     * 常用时间转换格式
     */
    public static final String DATE_FORMATTER_1 = "yyyy";
    public static final String DATE_FORMATTER_2 = "yyyy-MM";
    public static final String DATE_FORMATTER_3 = "yyyy-MM-dd";
    public static final String DATE_FORMATTER_4 = "yyyy-MM-dd HH:mm";
    public static final String DATE_FORMATTER_5 = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMATTER_6 = "yyyy-MM-dd HH:mm:ss.S";
    public static final String DATE_FORMATTER_7 = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String DATE_FORMATTER_8 = "yyyy-MM-dd HH:mm:ss.SSSSSSS";
    public static final String DATE_FORMATTER_9 = "yyyyMM";
    public static final String DATE_FORMATTER_10 = "yyyyMMdd";
    public static final String DATE_FORMATTER_11 = "yyyyMMddHHmmss";
    public static final String DATE_FORMATTER_12 = "yyyyMMdd HHmmss";
    public static final String DATE_FORMATTER_13 = "yyyyMMdd HHmmssSSS";
    public static final String DATE_FORMATTER_14 = "yyyyMMddHHmmssSSS";
    public static final String DATE_FORMATTER_15 = "yyyy-MM-dd'T'HH:mm:ss.SSSz";
    public static final String DATE_FORMATTER_16 = "yyyy.MM";
    public static final String DATE_FORMATTER_17 = "yyyy.MM.dd";
    public static final String DATE_FORMATTER_18 = "yyyy.MM.dd HH:mm";
    public static final String DATE_FORMATTER_19 = "yyyy.MM.dd HH:mm:ss";
    public static final String DATE_FORMATTER_20 = "yyyy.MM.dd HH:mm:ss.S";
    public static final String DATE_FORMATTER_21 = "yyyy.MM.dd HH:mm:ss.SSS";
    public static final String DATE_FORMATTER_22 = "yyyy.MM.dd HH:mm:ss.SSSSSSS";
    public static final String DATE_FORMATTER_23 = "yyyy/MM";
    public static final String DATE_FORMATTER_24 = "yyyy/MM/dd";
    public static final String DATE_FORMATTER_25 = "yyyy/MM/dd HH:mm";
    public static final String DATE_FORMATTER_26 = "yyyy/MM/dd HH:mm:ss";
    public static final String DATE_FORMATTER_27 = "yyyy/MM/dd HH:mm:ss.S";
    public static final String DATE_FORMATTER_28 = "yyyy/MM/dd HH:mm:ss.SSS";
    public static final String DATE_FORMATTER_29 = "yyyy/MM/dd HH:mm:ss.SSSSSSS";
    public static final String DATE_FORMATTER_30 = "yyyy年";
    public static final String DATE_FORMATTER_31 = "yyyy年MM月";
    public static final String DATE_FORMATTER_32 = "yyyy年MM月dd日";
    public static final String DATE_FORMATTER_33 = "yyyy年MM月dd日 HH时mm分";
    public static final String DATE_FORMATTER_34 = "yyyy年MM月dd日 HH时mm分ss秒";
    public static final String DATE_FORMATTER_35 = "HH:mm:ss";
    public static final String DATE_FORMATTER_36 = "HHmmss";
    public static final String DATE_FORMATTER_37 = "HHmmssSSS";
    public static final String DATE_FORMATTER_38 = "yyyy/M/d";
    public static final String DATE_FORMATTER_39 = "yyyy/MM/d";
    public static final String DATE_FORMATTER_40 = "yyyy/M/dd";

    /**
     * 日期时间格式化器映射表
     * 使用 HashMap 并保证线程安全
     */
    protected static final Map<String, DateTimeFormatter> DATE_TIME_FORMAT_MAP = new HashMap<>();

    static {
        // 初始化所有日期格式的格式化器
        Stream.of(
            DATE_FORMATTER_1, DATE_FORMATTER_2, DATE_FORMATTER_3, DATE_FORMATTER_4, DATE_FORMATTER_5,
            DATE_FORMATTER_6, DATE_FORMATTER_7, DATE_FORMATTER_8, DATE_FORMATTER_9, DATE_FORMATTER_10,
            DATE_FORMATTER_11, DATE_FORMATTER_12, DATE_FORMATTER_13, DATE_FORMATTER_14, DATE_FORMATTER_15,
            DATE_FORMATTER_16, DATE_FORMATTER_17, DATE_FORMATTER_18, DATE_FORMATTER_19, DATE_FORMATTER_20,
            DATE_FORMATTER_21, DATE_FORMATTER_22, DATE_FORMATTER_23, DATE_FORMATTER_24, DATE_FORMATTER_25,
            DATE_FORMATTER_26, DATE_FORMATTER_27, DATE_FORMATTER_28, DATE_FORMATTER_29, DATE_FORMATTER_30,
            DATE_FORMATTER_31, DATE_FORMATTER_32, DATE_FORMATTER_33, DATE_FORMATTER_34, DATE_FORMATTER_35,
            DATE_FORMATTER_36, DATE_FORMATTER_37, DATE_FORMATTER_38, DATE_FORMATTER_39, DATE_FORMATTER_40
        ).forEach(format -> DATE_TIME_FORMAT_MAP.put(format, DateTimeFormatter.ofPattern(format)));
    }

    /**
     * 获取日期格式
     * @param date 字符串
     * @return java.lang.String
     */
    public static String getDateStr(String date) {
        if (ObjectUtil.isEmpty(date)) {
            return null;
        }

        // 1. 处理纯数字格式
        if (RegexUtil.isDigit(date)) {
            return getDigitDateFormat(date);
        }

        // 2. 处理带分隔符的日期格式
        if (date.contains("-") || date.contains("/") || date.contains(".")) {
            return getSeparatorDateFormat(date);
        }

        // 3. 处理中文日期格式
        if (date.contains("年")) {
            return getChineseDateFormat(date);
        }

        // 4. 处理带空格的日期时间格式
        if (date.contains(" ")) {
            return getSpaceDateFormat(date);
        }

        // 5. 处理纯时间格式
        return getTimeFormat(date);
    }

    /**
     * 获取纯数字日期格式
     */
    private static String getDigitDateFormat(String date) {
        int length = date.length();
        if (length == 4) return DATE_FORMATTER_1;  // yyyy
        if (length == 6) return DATE_FORMATTER_9;  // yyyyMM
        if (length == 8) return DATE_FORMATTER_10; // yyyyMMdd
        if (length == 10) return DATE_FORMATTER_3; // yyyy-MM-dd (时间戳秒)
        if (length == 12) return DATE_FORMATTER_11; // yyyyMMddHHmm
        if (length == 13) return DATE_FORMATTER_5; // yyyy-MM-dd HH:mm:ss (时间戳毫秒)
        if (length == 14) return DATE_FORMATTER_11; // yyyyMMddHHmmss
        if (length == 17) return DATE_FORMATTER_14; // yyyyMMddHHmmssSSS
        return null;
    }

    /**
     * 获取带分隔符的日期格式
     */
    private static String getSeparatorDateFormat(String date) {
            if (date.contains("-")) {
            return getHyphenDateFormat(date);
        } else if (date.contains("/")) {
            return getSlashDateFormat(date);
        } else if (date.contains(".")) {
            return getDotDateFormat(date);
        }
        return null;
    }

    /**
     * 获取横线分隔的日期格式
     */
    private static String getHyphenDateFormat(String date) {
        if (date.matches("\\d{4}-\\d{1,2}-\\d{1,2}")) {
            return DATE_FORMATTER_3; // yyyy-MM-dd
        }
        if (date.matches("\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}")) {
            return DATE_FORMATTER_4; // yyyy-MM-dd HH:mm
        }
        if (date.matches("\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}")) {
            return DATE_FORMATTER_5; // yyyy-MM-dd HH:mm:ss
        }
        if (date.matches("\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}\\.\\d+")) {
            return DATE_FORMATTER_7; // yyyy-MM-dd HH:mm:ss.SSS
        }
        return null;
    }

    /**
     * 获取斜线分隔的日期格式
     */
    private static String getSlashDateFormat(String date) {
        if (date.matches("\\d{4}/\\d{1,2}/\\d{1,2}")) {
            int length = date.length();
            if (length == 8) return DATE_FORMATTER_38; // yyyy/M/d
            if (length == 9) {
                return date.matches("\\d{4}/\\d{2}/\\d") ?
                       DATE_FORMATTER_39 : // yyyy/MM/d
                       DATE_FORMATTER_40;  // yyyy/M/dd
            }
            if (length == 10) return DATE_FORMATTER_24; // yyyy/MM/dd
        }
        if (date.matches("\\d{4}/\\d{1,2}/\\d{1,2} \\d{1,2}:\\d{1,2}")) {
            return DATE_FORMATTER_25; // yyyy/MM/dd HH:mm
        }
        if (date.matches("\\d{4}/\\d{1,2}/\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}")) {
            return DATE_FORMATTER_26; // yyyy/MM/dd HH:mm:ss
        }
        return null;
    }

    /**
     * 获取点分隔的日期格式
     */
    private static String getDotDateFormat(String date) {
        if (date.matches("\\d{4}\\.\\d{1,2}\\.\\d{1,2}")) {
            return DATE_FORMATTER_17; // yyyy.MM.dd
        }
        if (date.matches("\\d{4}\\.\\d{1,2}\\.\\d{1,2} \\d{1,2}:\\d{1,2}")) {
            return DATE_FORMATTER_18; // yyyy.MM.dd HH:mm
        }
        if (date.matches("\\d{4}\\.\\d{1,2}\\.\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}")) {
            return DATE_FORMATTER_19; // yyyy.MM.dd HH:mm:ss
        }
        return null;
    }

    /**
     * 获取中文日期格式
     */
    private static String getChineseDateFormat(String date) {
        int length = date.length();
        if (length == 5) return DATE_FORMATTER_30;  // yyyy年
        if (length == 8) return DATE_FORMATTER_31;  // yyyy年MM月
        if (length == 11) return DATE_FORMATTER_32; // yyyy年MM月dd日
        if (length == 16) return DATE_FORMATTER_33; // yyyy年MM月dd日 HH时mm分
        if (length == 19) return DATE_FORMATTER_34; // yyyy年MM月dd日 HH时mm分ss秒
        return null;
    }

    /**
     * 获取带空格的日期时间格式
     */
    private static String getSpaceDateFormat(String date) {
        if (date.matches("\\d{8} \\d{6}")) {
            return DATE_FORMATTER_12; // yyyyMMdd HHmmss
        }
        if (date.matches("\\d{8} \\d{9}")) {
            return DATE_FORMATTER_13; // yyyyMMdd HHmmssSSS
        }
        return null;
    }

    /**
     * 获取纯时间格式
     */
    private static String getTimeFormat(String date) {
        if (date.matches("\\d{2}:\\d{2}:\\d{2}")) {
            return DATE_FORMATTER_35; // HH:mm:ss
        }
        if (date.length() == 6 && RegexUtil.isDigit(date)) {
            return DATE_FORMATTER_36; // HHmmss
        }
        if (date.length() == 9 && RegexUtil.isDigit(date)) {
            return DATE_FORMATTER_37; // HHmmssSSS
        }
        return null;
    }

    private static SimpleDateFormat getSdf(final String pattern) {
        ThreadLocal<SimpleDateFormat> tl = SDF_MAP.get(pattern);
        if (ObjectUtil.isEmpty(tl)) {
            synchronized (LOCK_OBJ) {
                tl = SDF_MAP.get(pattern);
                if (ObjectUtil.isEmpty(tl)) {
                    tl = ThreadLocal.withInitial(() -> new SimpleDateFormat(pattern));
                    SDF_MAP.put(pattern, tl);
                }
            }
        }
        return tl.get();
    }

    public static String format(Date date, String pattern) {
        return getSdf(pattern).format(date);
    }

    /**
     * 根据format的格式获取相应的DateTimeFormatter对象
     *
     * @param format 时间转换格式字符串
     * @return java.time.format.DateTimeFormatter
     */
    public static DateTimeFormatter getDateTimeFormatter(String format) {
        if (DATE_TIME_FORMAT_MAP.containsKey(format)) {
            return DATE_TIME_FORMAT_MAP.get(format);
        } else {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
            DATE_TIME_FORMAT_MAP.put(format, formatter);
            return formatter;
        }
    }

    /**
     * 获取本月的第一天，格式为自定义格式，默认格式为yyyy-MM-dd HH:mm:ss
     *
     * @return java.lang.String
     */
    public static String getFirstDayOfThisMonth(String pattern) {
        DateTimeFormatter formatter = null;
        if (ObjectUtil.isEmpty(pattern)) {
            formatter = getDateTimeFormatter(DATE_FORMATTER_5);
        } else {
            formatter = getDateTimeFormatter(pattern);
        }
        LocalDateTime firstDayOfThisYear = getCurrLocalDateTime().with(TemporalAdjusters.firstDayOfMonth());
        return formatter.format(firstDayOfThisYear);
    }

    /**
     * 获取本月第N天，格式为自定义格式，默认格式为yyyy-MM-dd HH:mm:ss
     * @param pattern 格式字符串
     * @return java.lang.String
     */
    public static String getNdayOfThisMonth (int n ,String pattern) {
        DateTimeFormatter formatter = null;
        if (ObjectUtil.isEmpty(n)) {
            throw new DateTimeException("Please enter the day of the month you want to get!");
        }
        if (ObjectUtil.isEmpty(pattern)) {
            formatter = getDateTimeFormatter(DATE_FORMATTER_5);
        } else {
            formatter = getDateTimeFormatter(pattern);
        }
        LocalDate secondDayOfThisMonth = LocalDate.now().withDayOfMonth(n);
        return formatter.format(secondDayOfThisMonth);
    }

    /**
     * 获取本月的最末天，格式为自定义格式，默认格式为yyyy-MM-dd HH:mm:ss
     *
     * @return java.lang.String
     */
    public static String getLastDayOfThisMonth(String pattern) {
        DateTimeFormatter formatter = null;
        if (ObjectUtil.isEmpty(pattern)) {
            formatter = getDateTimeFormatter(DATE_FORMATTER_5);
        } else {
            formatter = getDateTimeFormatter(pattern);
        }
        LocalDateTime firstDayOfThisYear = getCurrLocalDateTime().with(TemporalAdjusters.lastDayOfMonth());
        return formatter.format(firstDayOfThisYear);
    }

    /**
     * 当前时间往前推多少天
     * @param days 天数
     * @return java.time.LocalDateTime
     */
    public static LocalDateTime getLdtMinusDays (int days) {
        return getCurrLocalDateTime().minusDays(days);
    }

    /**
     * 从指定日期往前推多少天
     * @param obj 指定日期
     * @param days 向前推的天数
     * @return LocalDateTime 结果日期时间
     * @throws DateTimeException 当输入参数无效时抛出
     */
    public static LocalDateTime getLdtMinusDaysFromSpecifiedDate(Object obj, int days) {
        if (ObjectUtil.isEmpty(obj)) {
            throw new DateTimeException("Please enter the date you want to move back from!");
        }
        if (ObjectUtil.isEmpty(days)) {
            throw new DateTimeException("Please enter the number of days you want to move back from the current date!");
        }
        LocalDateTime dateTime = convertObjToLdt(obj);
        if (dateTime == null) {
            throw new DateTimeException("Failed to convert the specified date to LocalDateTime");
        }
        return dateTime.minusDays(days);
    }

    /**
     * 当前日期向后推多少天
     *
     * @param days 天数
     * @return java.time.LocalDateTime
     */
    public static LocalDateTime getLocalPlusDays(int days) {
        return getCurrLocalDateTime().plusDays(days);
    }

    /**
     * 当前日期向后推多少天,默认格式为yyyy-MM-dd
     *
     * @param days 天数
     * @return java.lang.String
     */
    public static String getStringPlusDays (int days) {
        if (ObjectUtil.isEmpty(days)) {
            throw new DateTimeException("Please enter the number of days you want to move back from the current date!");
        }
        return getStringPlusDays(days,DATE_FORMATTER_3);
    }

    /**
     * 当前日期向后推多少天，格式为自定义格式，默认格式为yyyy-MM-dd HH:mm:ss
     *
     * @param days 天数
     * @param pattern 格式字符串
     * @return java.lang.String
     */
    public static String getStringPlusDays (int days ,String pattern) {
        DateTimeFormatter formatter;
        if (ObjectUtil.isEmpty(days)) {
            throw new DateTimeException("Please enter the number of days you want to move back from the current date!");
        }
        if (ObjectUtil.isEmpty(pattern)) {
            formatter = getDateTimeFormatter(DATE_FORMATTER_5);
        } else {
            formatter = getDateTimeFormatter(pattern);
        }
        LocalDateTime localDateTime = getCurrLocalDateTime().plusDays(days);
        return formatter.format(localDateTime);
    }

    /**
     * 当前日期向后推多少天，格式为自定义格式，默认格式为yyyy-MM-dd HH:mm:ss
     *
     * @param obj 指定日期
     * @param days 向后推的天数
     * @return java.lang.String
     */
    public static String getStringPlusDays (Object obj,int days) {
        return getStringPlusDays(obj,days,DATE_FORMATTER_5);
    }

    /**
     * 当前日期向后推多少天，格式为自定义格式，默认格式为yyyy-MM-dd HH:mm:ss
     *
     * @param obj 指定日期
     * @param days 向后推的天数
     * @param pattern 格式字符串
     * @return 格式化后的日期字符串
     * @throws DateTimeException 当输入参数无效时抛出
     */
    public static String getStringPlusDays(Object obj, int days, String pattern) {
        if (ObjectUtil.isEmpty(obj)) {
            throw new DateTimeException("Please enter the date you want to move back from!");
        }
        if (ObjectUtil.isEmpty(days)) {
            throw new DateTimeException("Please enter the number of days you want to move back from the specify time!");
        }

        DateTimeFormatter formatter = ObjectUtil.isEmpty(pattern) ?
            getDateTimeFormatter(DATE_FORMATTER_5) :
            getDateTimeFormatter(pattern);

        LocalDateTime localDateTime = convertObjToLdt(obj);
        if (localDateTime == null) {
            throw new DateTimeException("Failed to convert the specified date to LocalDateTime");
        }

        return formatter.format(localDateTime.plusDays(days));
    }

    /**
     * 获取今天的00:00:00
     *
     * @return java.lang.String
     */
    public static String getDayStart() {
        return getDayStart(LocalDateTime.now());
    }

    /**
     * 获取今天的23:59:59
     *
     * @return java.lang.String
     */
    public static String getDayEnd() {
        return getDayEnd(LocalDateTime.now());
    }

    /**
     * 获取某天的00:00:00
     *
     * @param dateTime LocalDateTime对象
     * @return java.lang.String
     */
    public static String getDayStart(LocalDateTime dateTime) {
        if (ObjectUtil.isEmpty(dateTime)) {
            throw new DateTimeException("Please enter the localDateTime to be converted!");
        }
        return convertObjToString(dateTime.with(LocalTime.MIN));
    }

    /**
     * 获取某天的23:59:59
     *
     * @param dateTime LocalDateTime对象
     * @return java.lang.String
     */
    public static String getDayEnd(LocalDateTime dateTime) {
        if (ObjectUtil.isEmpty(dateTime)) {
            throw new DateTimeException("Please enter the localDateTime to be converted!");
        }
        return convertObjToString(dateTime.with(LocalTime.MAX));
    }

    /**
     * 获取本月第一天的00:00:00
     *
     * @return java.lang.String
     */
    public static String getFirstDayOfMonth() {
        return getFirstDayOfMonth(LocalDateTime.now());
    }

    /**
     * 获取本月最后一天的23:59:59
     *
     * @return java.lang.String
     */
    public static String getLastDayOfMonth() {
        return getLastDayOfMonth(LocalDateTime.now());
    }

    /**
     * 获取某月第一天的00:00:00
     *
     * @param dateTime
     *            LocalDateTime对象
     * @return java.lang.String
     */
    public static String getFirstDayOfMonth(LocalDateTime dateTime) {
        return convertObjToString(dateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN));
    }

    /**
     * 获取某月最后一天的23:59:59
     *
     * @param dateTime
     *            LocalDateTime对象
     * @return java.lang.String
     */
    public static String getLastDayOfMonth(LocalDateTime dateTime) {
        return convertObjToString(dateTime.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX));
    }

    /**
     * 获取几个月前的第一天
     * 比如现在是2022-09-20，获取3个月前的第一天，那就是2022-06-01
     * @return java.lang.String 默认格式为yyyy-MM-dd
     */
    public static String getLastMonthStartDay(int num,String pattern){
        if (ObjectUtil.isEmpty(num)) {
            throw new DateTimeException("Please enter the num parameters!");
        }
        if (ObjectUtil.isEmpty(pattern)) {
            pattern = DateUtil.DATE_FORMATTER_3;
        }
        LocalDate start =  LocalDate.now().minusMonths(num);
        LocalDate firstday = LocalDate.of(start.getYear(), start.getMonthValue(), 1);
        return convertObjToString(firstday,pattern);
    }

    /**
     * 获取上个月的最后一天
     * @return java.lang.String 默认格式为yyyy-MM-dd
     */
    public static String getLastMonthEndDay(String pattern){
        if (ObjectUtil.isEmpty(pattern)) {
            pattern = DateUtil.DATE_FORMATTER_3;
        }
        // 月份
        LocalDate end = LocalDate.now().minusMonths(1);
        //上个月的最后一天
        LocalDate lastMonthDay = end.with(TemporalAdjusters.lastDayOfMonth());
        return convertObjToString(lastMonthDay,pattern);
    }

    /**
     * 当前时间减N个月
     * @return java.lang.String 默认格式为yyyy-MM-dd HH:mm:ss
     */
    public static String getCurrDateTimeSubNMonth(int n){
        return getCurrDateTimeSubNMonth(n,DateUtil.DATE_FORMATTER_5);
    }

    /**
     * 当前时间减N个月
     * @return java.lang.String 默认格式为yyyy-MM-dd HH:mm:ss
     */
    public static String getCurrDateTimeSubNMonth(int n,String pattern){
        if (ObjectUtil.isEmpty(pattern)) {
            pattern = DateUtil.DATE_FORMATTER_5;
        }
        return convertObjToString(getCurrLocalDateTime().minusMonths(n),pattern);
    }

    /**
     * 当前时间加N个月
     * @return java.lang.String 默认格式为yyyy-MM-dd HH:mm:ss
     */
    public static String getCurrDateTimePlusNMonth(int n){
        return getCurrDateTimePlusNMonth(n,DateUtil.DATE_FORMATTER_5);
    }

    /**
     * 当前时间加N个月
     * @return java.lang.String 默认格式为yyyy-MM-dd HH:mm:ss
     */
    public static String getCurrDateTimePlusNMonth(int n,String pattern){
        if (ObjectUtil.isEmpty(pattern)) {
            pattern = DateUtil.DATE_FORMATTER_5;
        }
        return convertObjToString(getCurrLocalDateTime().plusMonths(n),pattern);
    }

    /**
     * 获取几个月前的最后一天
     * 比如现在是2022-09-20，获取3个月前的最后一天，那就是2022-06-30
     * @return java.lang.String 默认格式为yyyy-MM-dd
     */
    public static String getLastMonthsEndDay(int num,String pattern){
        if (ObjectUtil.isEmpty(num)) {
            throw new DateTimeException("Please enter the num parameters!");
        }
        if (ObjectUtil.isEmpty(pattern)) {
            pattern = DateUtil.DATE_FORMATTER_3;
        }
        // 月份
        LocalDate end = LocalDate.now().minusMonths(num);
        //上个月的最后一天
        LocalDate lastMonthDay = end.with(TemporalAdjusters.lastDayOfMonth());
        return convertObjToString(lastMonthDay,pattern);
    }

    /**
     * 获取几个月后的第一天
     * 比如现在是2022-09-20，获取1个月后的第一天，那就是2022-10-01
     * @return java.lang.String 默认格式为yyyy-MM-dd
     */
    public static String getNextMonthsStartDay(int num,String pattern){
        if (ObjectUtil.isEmpty(num)) {
            throw new DateTimeException("Please enter the num parameters!");
        }
        if (ObjectUtil.isEmpty(pattern)) {
            pattern = DateUtil.DATE_FORMATTER_3;
        }
        // 起始时间
        LocalDate start =  LocalDate.now().plusMonths(num);
        LocalDate firstday = LocalDate.of(start.getYear(), start.getMonthValue(), 1);
        return convertObjToString(firstday,pattern);
    }

    /**
     * 获取下个月的最后一天
     * @return java.lang.String 默认格式为yyyy-MM-dd
     */
    public static String getNextMonthEndDay(String pattern){
        if (ObjectUtil.isEmpty(pattern)) {
            pattern = DateUtil.DATE_FORMATTER_3;
        }
        //下个月的最后一天
        LocalDate nextMonthEndDay = LocalDate.now().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
        return convertObjToString(nextMonthEndDay,pattern);
    }

    /**
     * 获取下几月的最后一天
     * @return java.lang.String 默认格式为yyyy-MM-dd
     */
    public static String getNextMonthsEndDay(int num,String pattern){
        if (ObjectUtil.isEmpty(num)) {
            throw new DateTimeException("Please enter the num parameters!");
        }
        if (ObjectUtil.isEmpty(pattern)) {
            pattern = DateUtil.DATE_FORMATTER_3;
        }
        //下几个月的最后一天
        LocalDate nextMonthEndDay = LocalDate.now().plusMonths(num).with(TemporalAdjusters.lastDayOfMonth());
        return convertObjToString(nextMonthEndDay,pattern);
    }

    /**
     * 获取系统当前日期时间字符串，格式为yyyy-MM-dd HH:mm:ss
     *
     * @return java.lang.String
     */
    public static String getCurrDateTime(){
        return convertObjToString(getCurrLocalDateTime(),DateUtil.DATE_FORMATTER_5);
    }

    /**
     * 获取系统当前日期时间字符串
     *
     * @return java.lang.String
     */
    public static String getCurrDateTime(String pattern){
        if (ObjectUtil.isEmpty(pattern)) {
            pattern = DATE_FORMATTER_5;
        }
        return convertObjToString(getCurrLocalDateTime(),pattern);
    }

    /**
     * 获取系统当前日期时间字符串，格式为yyyy-MM-dd
     *
     * @return java.sql.Date
     */
    public static java.sql.Date getCurrSqlDate(){
        return convertObjToSqlDate(getCurrLocalDateTime());
    }

    /**
     * 获取系统当前日期时间字符串，格式为yyyy-MM-dd HH:mm:ss:SSS
     *
     * @return java.sql.Timestamp
     */
    @SneakyThrows
    public static Timestamp getCurrTimestamp(){
        return convertObjToTimestamp(LocalDateTime.now());
    }

    /**
     * 获取系统当前日期时间
     *
     * @return java.time.LocalDateTime
     */
    public static LocalDateTime getCurrLocalDateTime() {
        return LocalDateTime.now();
    }

    /**
     * 获取系统当前日期时间字符串，格式为自定义格式，默认格式为yyyy-MM-dd HH:mm:ss
     *
     * @return java.lang.String
     */
    public static String getCurrentLocalDate(String pattern) {
        return getCurrDateTime(pattern);
    }

    /**
     * 返回当前的日期
     *
     * @return java.time.LocalDate
     */
    public static LocalDate getCurrentLocalDate() {
        return LocalDate.now();
    }

    /**
     * 返回当前时间
     *
     * @return java.time.LocalTime
     */
    public static LocalTime getCurrentLocalTime() {
        return LocalTime.now();
    }


    /**
     * 获取两个日期的差  field参数为ChronoUnit.*
     * @param startTime 开始时间
     * @param endTime  结束时间
     * @param field  单位(年月日时分秒)
     * @return long
     */
    public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
        if (ObjectUtil.isEmpty(startTime)) {
            throw new DateTimeException("Please enter a start time!");
        }
        if (ObjectUtil.isEmpty(endTime)) {
            throw new DateTimeException("Please enter a end time!");
        }
        if (ObjectUtil.isEmpty(field)) {
            throw new DateTimeException("Please enter a time unit!");
        }
        Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
        if (field == ChronoUnit.YEARS) {
            return period.getYears();
        }
        if (field == ChronoUnit.MONTHS) {
            return period.getYears() * 12L + period.getMonths();
        }
        return field.between(startTime, endTime);
    }

    /**
     * 获取两个时间相差天数
     * @param startDateInclusive 开始时间
     * @param endDateExclusive 结束时间
     * @return long
     */
    public static long periodDays(LocalDate startDateInclusive, LocalDate endDateExclusive) {
        if (ObjectUtil.isEmpty(startDateInclusive)) {
            throw new DateTimeException("Please enter a start time!");
        }
        if (ObjectUtil.isEmpty(endDateExclusive)) {
            throw new DateTimeException("Please enter a end time!");
        }
        return endDateExclusive.toEpochDay() - startDateInclusive.toEpochDay();
    }

    /**
     * 日期相隔小时
     * @param startInclusive 开始时间
     * @param endExclusive 结束时间
     * @return long
     */
    public static long durationHours(Temporal startInclusive, Temporal endExclusive) {
        if (ObjectUtil.isEmpty(startInclusive)) {
            throw new DateTimeException("Please enter a start time!");
        }
        if (ObjectUtil.isEmpty(endExclusive)) {
            throw new DateTimeException("Please enter a end time!");
        }
        return Duration.between(startInclusive, endExclusive).toHours();
    }

    /**
     * 日期相隔分钟
     * @param startInclusive 开始时间
     * @param endExclusive 结束时间
     * @return long
     */
    public static long durationMinutes(Temporal startInclusive, Temporal endExclusive) {
        if (ObjectUtil.isEmpty(startInclusive)) {
            throw new DateTimeException("Please enter a start time!");
        }
        if (ObjectUtil.isEmpty(endExclusive)) {
            throw new DateTimeException("Please enter a end time!");
        }
        return Duration.between(startInclusive, endExclusive).toMinutes();
    }

    /**
     * 日期相隔毫秒数
     * @param startInclusive 开始时间
     * @param endExclusive 结束时间
     * @return long
     */
    public static long durationMillis(Temporal startInclusive, Temporal endExclusive) {
        if (ObjectUtil.isEmpty(startInclusive)) {
            throw new DateTimeException("Please enter a start time!");
        }
        if (ObjectUtil.isEmpty(endExclusive)) {
            throw new DateTimeException("Please enter a end time!");
        }
        return Duration.between(startInclusive, endExclusive).toMillis();
    }

    /**
     * 是否当天
     * @param date 日期
     * @return boolean
     */
    public static boolean isToday(LocalDate date) {
        if (ObjectUtil.isEmpty(date)) {
            throw new DateTimeException("Please enter a date!");
        }
        return getCurrentLocalDate().equals(date);
    }

    /**
     * 获取此日期时间与默认时区<Asia/Shanghai>组合的时间毫秒数
     * @param dateTime 日期时间
     * @return long 时间毫秒数
     */
    public static Long toEpochMilli(LocalDateTime dateTime) {
        if (ObjectUtil.isEmpty(dateTime)) {
            throw new DateTimeException("Please enter a localDateTime!");
        }
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 获取此日期时间与指定时区组合的时间毫秒数
     * @param dateTime 日期时间
     * @param zoneId 时区偏移量
     * @return long 时间毫秒数
     */
    public static Long toSelectEpochMilli(LocalDateTime dateTime, ZoneId zoneId) {
        if (ObjectUtil.isEmpty(dateTime)) {
            throw new DateTimeException("Please enter a localDateTime!");
        }
        if (ObjectUtil.isEmpty(zoneId)) {
            throw new DateTimeException("Please enter a zoneId!");
        }
        return dateTime.atZone(zoneId).toInstant().toEpochMilli();
    }

    /**
     * 判断是否为闰年
     * @param date 日期
     * @return boolean
     */
    public static boolean isLeapYear (LocalDate date) {
        if (ObjectUtil.isEmpty(date)) {
            throw new DateTimeException("Please Enter a LocalDate!");
        }
        return date.isLeapYear();
    }

    /**
     * 获取当前的ZoneDateTime
     *
     * @param zoneId 时区偏移量
     * @return java.time.ZonedDateTime 时间
     */
    public static ZonedDateTime now(ZoneId zoneId) {
        if (ObjectUtil.isEmpty(zoneId)) {
            throw new DateTimeException("Please enter a zoneId!");
        }
        return ZonedDateTime.now(zoneId);
    }

    /**
     * 获取当前日期的开始时间ZonedDateTime
     *
     * @param date   日期
     * @param zoneId 时区偏移量
     * @return java.time.ZonedDateTime 时间
     */
    public static ZonedDateTime ldToZoneDateTime(LocalDate date, ZoneId zoneId) {
        if (ObjectUtil.isEmpty(date)) {
            throw new DateTimeException("Please enter a LocalDate!");
        }
        if (ObjectUtil.isEmpty(zoneId)) {
            throw new DateTimeException("Please enter a zoneId!");
        }
        return date.atStartOfDay(zoneId);
    }

    /**
     * 获取当前日期的开始时间
     *
     * @param dateTime 日期时间
     * @return java.time.ZonedDateTime 时间
     */
    public static LocalDateTime startOfDay(ZonedDateTime dateTime) {
        if (ObjectUtil.isEmpty(dateTime)) {
            throw new DateTimeException("Please enter a ZonedDateTime!");
        }
        return dateTime.truncatedTo(ChronoUnit.DAYS).toLocalDateTime();
    }

    /**
     * 获取今天后的指定天数的开始时间
     *
     * @param plusDays 当前多少天后
     * @param zoneId   时区偏移量
     * @return java.time.ZonedDateTime 时间
     */
    public static LocalDateTime startOfDay(int plusDays, ZoneId zoneId) {
        if (ObjectUtil.isEmpty(plusDays)) {
            throw new DateTimeException("Please enter the specified number of days after today!");
        }
        if (ObjectUtil.isEmpty(zoneId)) {
            throw new DateTimeException("Please enter a zoneId!");
        }
        return startOfDay(now(zoneId).plusDays(plusDays));
    }

    /**
     * 获取指定日期的后几个工作日的时间LocalDate
     *
     * @param date 指定日期
     * @param days 工作日数
     * @return java.time.LocalDate 日期
     */
    public static LocalDate plusWeekdays(LocalDate date, int days) {
        if (days == 0) {
            return date;
        }
        if (Math.abs(days) > 50) {
            throw new IllegalArgumentException("days must be less than 50");
        }
        int i = 0;
        int delta = days > 0 ? 1 : -1;
        while (i < Math.abs(days)) {
            date = date.plusDays(delta);
            DayOfWeek dayOfWeek = date.getDayOfWeek();
            if (dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY) {
                i += 1;
            }
        }
        return date;
    }

    /**
     * 获取指定时间的上一个工作日
     *
     * @param time           指定时间
     * @param formattPattern 格式化参数
     * @return java.lang.String 日期字符串
     */
    public static String getPreWorkDay(String time, String formattPattern) {
        DateTimeFormatter dateTimeFormatter = generateDefualtPattern(formattPattern);
        LocalDateTime compareTime1 = LocalDateTime.parse(time, dateTimeFormatter);
        compareTime1 = compareTime1.with(temporal -> {
            // 当前日期
            DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
            // 正常情况下，每次减去一天
            int dayToMinu = 1;
            // 如果是周日，减去2天
            if (dayOfWeek == DayOfWeek.SUNDAY) {
                dayToMinu = 2;
            }
            // 如果是周六，减去一天
            if (dayOfWeek == DayOfWeek.SATURDAY) {
                dayToMinu = 1;
            }
            return temporal.minus(dayToMinu, ChronoUnit.DAYS);
        });
        return compareTime1.format(dateTimeFormatter);
    }


    /**
     * 获取指定时间的下一个工作日
     *
     * @param time           指定时间
     * @param formattPattern 格式参数
     * @return java.lang.String 日期字符串
     */
    public static String getNextWorkDay(String time, String formattPattern) {
        DateTimeFormatter dateTimeFormatter = generateDefualtPattern(formattPattern);
        LocalDateTime compareTime1 = LocalDateTime.parse(time, dateTimeFormatter);
        compareTime1 = compareTime1.with(temporal -> {
            // 当前日期
            DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
            // 正常情况下，每次增加一天
            int dayToAdd = 1;
            // 如果是星期五，增加三天
            if (dayOfWeek == DayOfWeek.FRIDAY) {
                dayToAdd = 3;
            }
            // 如果是星期六，增加两天
            if (dayOfWeek == DayOfWeek.SATURDAY) {
                dayToAdd = 2;
            }
            return temporal.plus(dayToAdd, ChronoUnit.DAYS);
        });
        return compareTime1.format(dateTimeFormatter);
    }

    /**
     * 生成默认的格式器
     *
     * @param timeFormat 指定格式
     * @return 默认时间格式器
     */
    private static DateTimeFormatter generateDefualtPattern(String timeFormat) {
        return new DateTimeFormatterBuilder().appendPattern(timeFormat)
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                .toFormatter(Locale.CHINA);
    }

    /**
     * 获取指定日期的后几个工作日的时间ZoneDateTime
     *
     * @param date 指定日期
     * @param days 工作日数
     * @return java.time.ZonedDateTime 时间
     */
    public static ZonedDateTime plusWeekdays(ZonedDateTime date, int days) {
        if (ObjectUtil.isEmpty(date)) {
            throw new DateTimeException("Please enter a ZonedDateTime!");
        }
        if (ObjectUtil.isEmpty(days)) {
            throw new DateTimeException("Please enter the working day after the specified date!");
        }
        return plusWeekdays(date.toLocalDate(), days).atStartOfDay(date.getZone());
    }

    /**
     * 获取当前月份的第一天的时间ZoneDateTime
     *
     * @param zoneId 时区偏移量
     * @return java.time.ZonedDateTime 时间
     */
    public static ZonedDateTime firstDayOfMonth(ZoneId zoneId) {
        if (ObjectUtil.isEmpty(zoneId)) {
            throw new DateTimeException("Please enter a ZoneId!");
        }
        return now(zoneId).withDayOfMonth(1);
    }

    /**
     * 两个时区的zoneDateTime相互转换
     *
     * @param zonedDateTime 需要转换的如期
     * @param zoneId        转换成的ZoneDateTime的时区偏移量
     * @return java.time.ZonedDateTime 时间
     */
    public static ZonedDateTime zdtToZdt(ZonedDateTime zonedDateTime, ZoneId zoneId) {
        if (ObjectUtil.isEmpty(zonedDateTime)) {
            throw new DateTimeException("Please enter a ZonedDateTime object to be converted!");
        }
        ZonedDateTime zdt = null;
        try {
            zdt =  ZonedDateTime.ofInstant(zonedDateTime.toInstant(), zoneId);
        } catch (DateTimeException e){
            throw new DateTimeException("Date conversion exception!");
        }
        return zdt;
    }

    /**
     * 将ZonedDateTime转成时间戳long
     * @param zonedDateTime 需要转换的ZonedDateTime
     * @return long 时间戳
     */
    public static long zoneDateTimeToLong(ZonedDateTime zonedDateTime) {
        if (ObjectUtil.isEmpty(zonedDateTime)) {
            throw new DateTimeException("Please enter the ZonedDateTime Object to be converted!");
        }
        long timeStamp;
        try {
            timeStamp = zonedDateTime.toInstant().toEpochMilli();
        } catch (DateTimeException e){
            throw new DateTimeException("Date conversion exception!");
        }
        return timeStamp;
    }

    /**
     * 将LocalDateTime转成时间戳long
     *
     * @param localDateTime 需要转换的LocalDateTime
     * @param zoneId 时区偏移量
     * @return long 时间戳
     */
    public static long toLong(LocalDateTime localDateTime, ZoneId zoneId) {
        if (ObjectUtil.isEmpty(localDateTime)) {
            throw new DateTimeException("Please enter the LocalDateTime Object to be converted!");
        }
        long timeStamp;
        try {
            timeStamp = zoneDateTimeToLong(localDateTime.atZone(zoneId));
        } catch (DateTimeException e){
            throw new DateTimeException("Date conversion exception!");
        }
        return timeStamp;
    }

    /**
     * 获取周第一天
     *
     * @param date 待获取周第一天的日期
     * @return java.time.LocalDate 日期
     */
    public static Date getStartDayOfWeek(String date) {
        if (ObjectUtil.isEmpty(date)) {
            throw new DateTimeException("Please enter the date string to be converted!");
        }
        Date dt;
        try {
            LocalDate now = LocalDate.parse(date);
            dt =  getStartDayOfWeek(now);
        } catch (DateTimeException e){
            throw new DateTimeException("Date conversion exception!");
        }
        return dt;
    }

    public static Date getStartDayOfWeek(TemporalAccessor date) {
        TemporalField fieldISO = WeekFields.of(Locale.CHINA).dayOfWeek();
        LocalDate localDate = LocalDate.from(date);
        localDate = localDate.with(fieldISO, 1);
        return convertObjToUtilDate(localDate);
    }

    /**
     * 获取周最后一天
     *
     * @param date 待获取周最后一天的日期
     * @return java.time.LocalDate 日期
     */
    public static Date getEndDayOfWeek(String date) {
        if (ObjectUtil.isEmpty(date)) {
            throw new DateTimeException("Please enter the date string to be converted!");
        }
        Date dt;
        try {
            LocalDate now = LocalDate.parse(date);
            dt =  getEndDayOfWeek(now);
        } catch (DateTimeException e){
            throw new DateTimeException("Date conversion exception!");
        }
        return dt;
    }

    public static Date getEndDayOfWeek(TemporalAccessor date) {
        TemporalField fieldISO = WeekFields.of(Locale.CHINA).dayOfWeek();
        LocalDate localDate = LocalDate.from(date);
        localDate = localDate.with(fieldISO, 7);
        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).plusDays(1L).minusNanos(1L).toInstant());
    }

    /**
     * 将字符串转换为Timestamp对象
     * @param date 日期时间字符串
     * @return Timestamp对象
     * @throws BusinessException 当日期格式无法识别或转换失败时抛出
     */
    public static Timestamp stringToTimestamp(String date) throws BusinessException {
        if (ObjectUtil.isEmpty(date)) {
            return null;
        }

        try {
            // 1. 处理数字时间戳
            if (RegexUtil.isDigit(date)) {
                return handleNumericTimestamp(date);
            }

            // 2. 处理带T的ISO格式
            if (date.contains("T")) {
                return handleIsoFormat(date);
            }

            // 3. 处理带空格的日期时间格式
            if (date.contains(" ")) {
                return handleDateTimeWithSpace(date);
            }

            // 4. 处理普通日期格式
            return handleSimpleDateFormat(date);

        } catch (ParseException e) {
            log.error("时间转换异常: {}", e.getMessage());
            throw new BusinessException("时间[" + date + "]转换异常: " + e.getMessage());
        } catch (NumberFormatException e) {
            log.error("时间戳转换异常: {}", e.getMessage());
            throw new BusinessException("时间戳[" + date + "]转换异常: " + e.getMessage());
        } catch (Exception e) {
            log.error("时间转换异常: {}", e.getMessage());
            throw new BusinessException("时间[" + date + "]转换异常: " + e.getMessage());
        }
    }

    /**
     * 处理数字时间戳
     */
    private static Timestamp handleNumericTimestamp(String date) {
        long timestamp;
        if (date.length() == 10) {
            timestamp = Long.parseLong(date) * 1000; // 秒转毫秒
        } else if (date.length() == 13) {
            timestamp = Long.parseLong(date);
        } else {
            // 处理纯数字日期格式
            String dateStr = getDateStr(date);
            if (ObjectUtil.isEmpty(dateStr)) {
                throw new BusinessException("无法识别的日期格式: " + date);
            }
            SimpleDateFormat sdf = getSdf(dateStr);
            try {
                Date parsedDate = sdf.parse(date);
                return new Timestamp(parsedDate.getTime());
            } catch (ParseException e) {
                throw new BusinessException("日期解析失败: " + date);
            }
        }
        return new Timestamp(timestamp);
    }

    /**
     * 处理ISO格式日期时间
     */
    private static Timestamp handleIsoFormat(String date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMATTER_15);
        LocalDateTime localDateTime = LocalDateTime.parse(date, formatter);
        return Timestamp.valueOf(localDateTime);
    }

    /**
     * 处理带空格的日期时间格式
     */
    private static Timestamp handleDateTimeWithSpace(String date) throws ParseException {
        String[] parts = date.split(" ");
        if (parts.length != 2) {
            throw new BusinessException("无效的日期时间格式: " + date);
        }

        String datePart = parts[0];
        String timePart = parts[1];

        // 处理日期部分
        String dateFormat = getDateStr(datePart);
        if (ObjectUtil.isEmpty(dateFormat)) {
            throw new BusinessException("无法识别的日期格式: " + date);
        }

        // 处理时间部分
        String timeFormat = determineTimeFormat(timePart);

        // 组合日期和时间
        SimpleDateFormat sdf = getSdf(dateFormat + " " + timeFormat);
        Date parsedDate = sdf.parse(date);
        return new Timestamp(parsedDate.getTime());
    }

    /**
     * 确定时间部分的格式
     */
    private static String determineTimeFormat(String timePart) {
        if (timePart.matches("\\d{1,2}:\\d{1,2}")) {
            return "HH:mm";
        } else if (timePart.matches("\\d{1,2}:\\d{1,2}:\\d{1,2}")) {
            return DATE_FORMATTER_35;
        } else if (timePart.matches("\\d{1,2}:\\d{1,2}:\\d{1,2}\\.\\d+")) {
            return "HH:mm:ss.SSS";
        } else if (timePart.matches("\\d{6}")) {
            return DATE_FORMATTER_36; // HHmmss
        } else if (timePart.matches("\\d{4}")) {
            return "HHmm";
        } else {
            throw new BusinessException("无法识别的时间格式: " + timePart);
        }
    }

    /**
     * 处理简单日期格式
     */
    private static Timestamp handleSimpleDateFormat(String date) throws ParseException {
        String dateStr = getDateStr(date);
        if (ObjectUtil.isEmpty(dateStr)) {
            throw new BusinessException("无法识别的日期格式: " + date);
        }
        SimpleDateFormat sdf = getSdf(dateStr);
        Date parsedDate = sdf.parse(date);
        return new Timestamp(parsedDate.getTime());
    }

    public static Date parse(String dateStr, String pattern)
            throws ParseException {
        return getSdf(pattern).parse(dateStr);
    }

    /**
     * Object转成Timestamp<br>
     * 能转换成Timestamp的有yyyy-MM-dd、yyyy/MM/dd、yyyy.MM.dd、yyyy-MM-dd HH:mm、yyyy-MM-dd HH:mm:ss、yyyy-MM-dd HH:mm:ss:SSS、
     * yyyyMMdd HHmmss、yyMMddHHmmss、yyyyMMdd HHmmssSSS、yyyyMMddHHmmssSSS格式的时间字符串，以及java.util.Date、java.sql.Date、
     * LocalDate、LocalDateTime
     * @param obj 待转换的对象
     * @return java.sql.Timestamp
     */
    @SneakyThrows
    public static Timestamp  convertObjToTimestamp(Object obj) {
        Timestamp timestamp = null;
        if (ObjectUtil.isEmpty(obj)) {
            return null;
        }
        if (obj instanceof Timestamp) {
            timestamp = (Timestamp) obj;
        } else if (obj instanceof String) {
            timestamp = stringToTimestamp((String)obj);
        } else if (obj instanceof Date) {
            timestamp = new Timestamp(((Date)obj).getTime());
        } else if (obj instanceof java.sql.Date) {
            long l = ((java.sql.Date)obj).getTime();
            timestamp = new Timestamp(l);
        } else if (obj instanceof LocalDate) {
            //毫秒时间戳
            long l = ((LocalDate)obj).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
            timestamp = new Timestamp(l);
        } else if (obj instanceof LocalDateTime) {
            //毫秒时间戳
            long l = ((LocalDateTime)obj).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            timestamp = new Timestamp(l);
        } else if (obj instanceof ZonedDateTime) {
            timestamp = Timestamp.valueOf(((ZonedDateTime)obj).toLocalDateTime());
        } else if (obj instanceof Instant) {
            timestamp = Timestamp.from((Instant)obj);
        } else if (obj instanceof Long) {
            timestamp = new Timestamp((Long)obj);
        } else {
            throw new ClassCastException("Not possible to coerce [" + obj + "] from class " + obj.getClass()
                    + " into a Timestamp.");
        }
        return timestamp;
    }

    /**
     * Object转成java.sql.Date
     * @param obj 待转换的对象
     * @return java.sql.Date 转换后的日期对象，如果输入为null则返回null
     */
    @SneakyThrows
    public static java.sql.Date convertObjToSqlDate(Object obj) {
        if (ObjectUtil.isEmpty(obj)) {
            return null;
        }
        Timestamp timestamp = convertObjToTimestamp(obj);
        return timestamp == null ? null : new java.sql.Date(timestamp.getTime());
    }

    /**
     * Object转成java.util.Date
     * @param obj 待转换的对象
     * @return java.util.Date 时间
     */
    @SneakyThrows
    public static Date convertObjToUtilDate(Object obj){
        if (ObjectUtil.isEmpty(obj)) {
            return null;
        }
        return new Date(Objects.requireNonNull(convertObjToTimestamp(obj)).getTime());
    }

    /**
     * Object转成DateTime
     * @param obj 待转换的对象
     * @return DateTime 时间
     */
    @SneakyThrows
    public static DateTime convertObjToDateTime(Object obj){
        if (ObjectUtil.isEmpty(obj)) {
            return null;
        }
        Date date1 = convertObjToUtilDate(obj);
        return new DateTime(Objects.requireNonNull(date1).getTime());
    }

    /**
     * Object转LocalDateTime类型的日期
     * @param obj 待转换的对象
     * @return LocalDateTime 转换后的日期时间对象，如果输入为null则返回null
     */
    @SneakyThrows
    public static LocalDateTime convertObjToLdt(Object obj) {
        if (ObjectUtil.isEmpty(obj)) {
            return null;
        }
        Timestamp timestamp = convertObjToTimestamp(obj);
        return timestamp == null ? null : timestamp.toLocalDateTime();
    }

    /**
     * Object转String类型的日期，格式默认为yyyy-MM-dd HH:mm:ss
     * @param obj 待转换的对象
     * @return java.lang.String 时间
     */
    @SneakyThrows
    public static String convertObjToString(Object obj){
        return convertObjToString(obj, DATE_FORMATTER_5);
    }

    /**
     * Object按指定日期格式转String类型的日期
     * @param obj 待转换的对象
     * @param pattern 日期格式
     * @return java.lang.String 时间
     */
    @SneakyThrows
    public static String convertObjToString(Object obj,String pattern){
        DateFormat sdf = new SimpleDateFormat(pattern);
        Timestamp timestamp =  convertObjToTimestamp(obj);
        String time = null;
        if (ObjectUtil.isNotEmpty(timestamp)) {
            time = sdf.format(timestamp);
        }
        return time;
    }

    /**
     * Object转成java.time.ZonedDateTime
     * @param obj 待转换的对象
     * @return java.lang.String 时间
     */
    @SneakyThrows
    public static ZonedDateTime convertObjToZdt(Object obj){
        if (ObjectUtil.isEmpty(obj)) {
            return null;
        }
        Timestamp timestamp =  convertObjToTimestamp(obj);
        return ZonedDateTime.ofInstant(Objects.requireNonNull(timestamp).toInstant(), ZoneId.systemDefault());
    }

    /**
     * Object转成java.time.Instant
     * @param obj 待转换的对象
     * @return java.time.Instant 时间
     */
    @SneakyThrows
    public static Instant convertObjToInstant(Object obj){
        if (ObjectUtil.isEmpty(obj)) {
            return null;
        }
        Timestamp timestamp =  convertObjToTimestamp(obj);
        Date date = new Date(Objects.requireNonNull(timestamp).getTime());
        return date.toInstant();
    }

    /**
     * Object转LocalDate类型的日期
     * @param obj 待转换的对象
     * @return LocalDate 转换后的日期对象，如果输入为null则返回null
     */
    @SneakyThrows
    public static LocalDate convertObjToLd(Object obj) {
        if (ObjectUtil.isEmpty(obj)) {
            return null;
        }
        Timestamp timestamp = convertObjToTimestamp(obj);
        return timestamp == null ? null : timestamp.toLocalDateTime().toLocalDate();
    }

    /**
     * 查询上个月的今天，如果当前时间是5月31号，上个月没有31号，那么只能显示4月30号
     * @return java.lang.String 日期字符串
     */
    public static String getDayOfLastMonth() {
        LocalDate date = LocalDate.now();
        // 当前月份减1
        LocalDate lastMonth = date.minusMonths(1);
        return convertObjToString(lastMonth);
    }

    /**
     * 指定时间减一个月
     * @param dateTime 时间字符串
     * @return java.lang.String 日期字符串
     */
    public static String getDayOfLastMonth(String dateTime) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(DATE_FORMATTER_3);
        LocalDate date = LocalDate.parse(dateTime, fmt);
        // 当前月份减1
        LocalDate lastMonth = date.minusMonths(1);
        return convertObjToString(lastMonth);
    }

	/**
     * 比较日期大小
     * <p>obj1或者obj2为空，返回-1</p>
     * <p>obj1早于obj2，返回0</p>
     * <p>obj1晚于obj2，返回1</p>
     * <p>obj1等于obj2，返回2</p>
     * @param obj1 第一个日期对象
     * @param obj2 第二个日期对象
     * @return int 比较结果
     */
    public static int compareDate(Object obj1, Object obj2) {
        if (ObjectUtil.isEmpty(obj1) || ObjectUtil.isEmpty(obj2)) {
            return -1;
        }
        LocalDateTime ld1 = convertObjToLdt(obj1);
        LocalDateTime ld2 = convertObjToLdt(obj2);
        if (ld1 == null || ld2 == null) {
            return -1;
        }
        if (ld1.isBefore(ld2)) {
            return 0;
        } else if (ld1.isAfter(ld2)) {
            return 1;
        } else {
            return 2;
        }
    }

}
